package tree.traversal;

import java.util.*;
import java.util.function.Function;

/**
 * Created by admin on 2019/1/25.
 */

public abstract class TreeTraversalBase<T> {
    public TreeTraversalBase() {
    }

    protected abstract List<T> getChildren(T var1);

    protected void setParent(T node, T parent) {
    }

    public void breadthFirstTraversal(T node, Function<T, Boolean> filter, Function<T, Boolean> process) {
        if(node != null) {
            LinkedList queen = new LinkedList();
            boolean isNext = true;
            queen.offer(node);

            while(queen.size() > 0) {
                node = (T)queen.poll();
                this.apply(node, filter, process);
                if(!isNext) {
                    break;
                }

                Iterator var6 = this.getChildren(node).iterator();

                while(var6.hasNext()) {
                    Object item = var6.next();
                    queen.offer(item);
                }
            }

        }
    }

    private boolean apply(T node, Function<T, Boolean> filter, Function<T, Boolean> process) {
        boolean isNext = true;
        if(filter == null || ((Boolean)filter.apply(node)).booleanValue()) {
            isNext = ((Boolean)process.apply(node)).booleanValue();
        }

        return isNext;
    }

    public void breadthTraversalWithParent(T node, Function<T, Boolean> filter, Function<T, Boolean> process) {
        if(node != null) {
            boolean isNext = true;
            this.apply(node, filter, process);
            LinkedList queen = new LinkedList();
            queen.offer(node);

            while(queen.size() > 0) {
                node = (T) queen.poll();
                List children = this.getChildren(node);
                if(children != null) {
                    int size = children.size();

                    for(int i = size - 1; i >= 0; --i) {
                        Object item = children.get(i);
                        if(item != null) {
                            this.setParent((T)item, node);
                        }

                        this.apply((T)item, filter, process);
                        if(!isNext) {
                            break;
                        }

                        queen.offer(item);
                    }

                    if(!isNext) {
                        break;
                    }
                }
            }

        }
    }

    //public PagedList<T> getPagedList(PagedIn in, T root, Function<T, Boolean> filter, Function<T, Boolean> isContinue) {
    //    PagedList pagedList = new PagedList();
    //    ArrayList result = new ArrayList();
    //    int ind = in.getPageIndex() * in.getPageSize();
    //    this.breadthFirstTraversal(root, filter, (m) -> {
    //        pagedList.setRecordCount(pagedList.getRecordCount() + 1);
    //        if(pagedList.getRecordCount() > ind && result.size() < in.getPageSize()) {
    //            result.add(m);
    //        }
    //
    //        return (Boolean)isContinue.apply(m);
    //    });
    //    pagedList.setPageIndex(in.getPageIndex());
    //    pagedList.setPageSize(in.getPageSize());
    //    pagedList.setList(result);
    //    return pagedList;
    //}

    public void sort(T node, Comparator<T> compare) {
        this.sort(node, compare, true);
    }

    public void sort(T node, Comparator<T> compare, boolean isAsc) {
        Comparator c = isAsc?compare:compare.reversed();
        this.breadthFirstTraversal(node, (Function)null, (x) -> {
            List list = this.getChildren(x);
            if(list != null && list.size() > 1) {
                Collections.sort(list, c);
            }

            return Boolean.valueOf(true);
        });
    }
}
